#include "include/Btree.h"
#include "GameStatus.h"

GameinfoDef gameinfo;
class BGameTime : public ConditionNode
{
public:
    BGameTime(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.RemainTime >= 360)
        {
            index = 1;
            cout << "1" << '\n';
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class MGameTime : public ConditionNode
{
public:
    MGameTime(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.RemainTime >= 180 && gameinfo.RemainTime <= 360)
        {
            index = 2;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class EGameTime : public ConditionNode
{
public:
    EGameTime(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.RemainTime >= 0 && gameinfo.RemainTime <= 180)
        {
            index = 3;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class _359GameTime : public ConditionNode
{
public:
    _359GameTime(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.RemainTime <= 300 && gameinfo.RemainTime >= 240)
        {
            index = 4;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class _645GameTime : public ConditionNode
{
public:
    _645GameTime(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.RemainTime >= 405 && gameinfo.RemainTime <= 425)
        {
            index = 5;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class Missile : public ConditionNode
{
public:
    Missile(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        cout << "3" << '\n';
        int index;
        if (gameinfo.isMissile == 1)
        {
            index = 6;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class Invasion : public ConditionNode
{
public:
    Invasion(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.inInvasion == 1)
        {
            index = 7;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class HP : public ConditionNode
{
public:
    HP(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.RobotHP == 100)
        {
            index = 8;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class SHP : public ConditionNode
{
public:
    SHP(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.SHP <= 200)
        {
            index = 9;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class FHP : public ConditionNode
{
public:
    FHP(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.FHP <= 200)
        {
            index = 10;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class AHP : public ConditionNode
{
public:
    AHP(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.RemainTime >= 1000)
        {
            index = 11;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class Buff : public ConditionNode
{
public:
    Buff(const std::string &name, const NodeConfiguration &config) : ConditionNode(name, config)
    {
    }

    NodeStatus tick() override
    {
        int index;
        if (gameinfo.BuffAvailable)
        {
            index = 12;
            gameinfo.index = index;
            return NodeStatus::SUCCESS;
        }
        return NodeStatus::FAILURE;
    }
    static PortsList providedPorts()
    {
        return {OutputPort<>("CarMessage")};
    }
};

class SendToOtherRobot : public SyncActionNode
{
public:
    SendToOtherRobot(const std::string &name, const NodeConfiguration &config) : SyncActionNode(name, config)
    {
    }

    NodeStatus tick() override
    {

        //串口发消息
        /* if (gameinfo.index != -1)
        {
            //gameinfo.previndex = gameinfo.index;
        } */

        return NodeStatus::SUCCESS;
    }

    static PortsList providedPorts()
    {
        // Optionally, a port can have a human readable description
        const char *description = "CarCommuniction...";
        return {InputPort<int>("CarMessage", description)};
    }
};

Tree init_BT(BehaviorTreeFactory &factory)
{

    factory.registerNodeType<SendToOtherRobot>("SendToOtherRobot");
    factory.registerNodeType<BGameTime>("BGameTime");
    factory.registerNodeType<MGameTime>("MGameTime");
    factory.registerNodeType<EGameTime>("EGameTime");
    factory.registerNodeType<_645GameTime>("_645GameTime");
    factory.registerNodeType<_359GameTime>("_359GameTime");
    factory.registerNodeType<HP>("HP");
    factory.registerNodeType<SHP>("SHP");
    factory.registerNodeType<AHP>("AHP");
    factory.registerNodeType<FHP>("FHP");
    factory.registerNodeType<Buff>("Buff");
    factory.registerNodeType<Missile>("Missile");
    factory.registerNodeType<Invasion>("Invasion");

    auto tree = factory.createTreeFromFile(param.treefile);
    return tree;
}

void dataprocess(string json)
{
    Json::Reader reader;
    Json::Value root;
    reader.parse(json, root, false);
    gameinfo.RemainTime = root["RemainTime"].asInt();
    gameinfo.BuffAvailable = root["BuffAvailable"].asInt();
    gameinfo.AHP = root["AHP"].asInt();
    gameinfo.FHP = root["FHP"].asInt();
    gameinfo.SHP = root["SHP"].asInt();
    gameinfo.inInvasion = root["inInvasion"].asInt();
}
